package com.bestcem.xm.txtanls.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.ObjectId;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.common.core.uitls.StringUtil;
import com.bestcem.xm.txtanls.dao.AnalysisProjectDao;
import com.bestcem.xm.txtanls.dao.JoinInfoDao;
import com.bestcem.xm.txtanls.dao.RecordDao;
import com.bestcem.xm.txtanls.dao.SurveyTxtanlsFieldDao;
import com.bestcem.xm.txtanls.entity.mongo.AnalysisProject;
import com.bestcem.xm.txtanls.entity.mongo.JoinInfo;
import com.bestcem.xm.txtanls.entity.mysql.JoinInfoViewpointEntity;
import com.bestcem.xm.txtanls.entity.pojo.ProjectDO;
import com.bestcem.xm.txtanls.entity.pojo.ProjectFieldDO;
import com.bestcem.xm.txtanls.entity.pojo.RecordDO;
import com.bestcem.xm.txtanls.entity.pojo.ViewpointDO;
import com.bestcem.xm.txtanls.enums.DatasourceEnum;
import com.bestcem.xm.txtanls.enums.IndustryCodeEnum;
import com.bestcem.xm.txtanls.enums.RecordSentiEnum;
import com.bestcem.xm.txtanls.enums.TrainStatusEnum;
import com.bestcem.xm.txtanls.grpc.client.BaseBiGrpcService;
import com.bestcem.xm.txtanls.service.dto.train.SentimentDTO;
import com.bestcem.xm.txtanls.service.dto.train.TrainTextDTO;
import com.bestcem.xm.txtanls.service.dto.user.IndustryDTO;
import com.bestcem.xm.txtanls.service.dto.worktable.ColumnDTO;
import com.zy.dp.proto.strontium.v1.OpinionSentiment;
import com.zy.dp.proto.strontium.v1.TextSentiment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author XiaoYunSong <ys.xiao@idiaoyan.com>
 * @version v1.0
 * @date 2021/6/8 17:34
 */
@Slf4j
@Component
public class AsyncTaskUtil {

    @Resource
    private SurveyTxtanlsFieldDao surveyTxtanlsFieldDao;
    @Resource
    private RecordDao recordDao;
    @Resource
    private JoinInfoDao joinInfoDao;
    @Resource
    private AnalysisProjectDao analysisProjectDao;

    @Resource
    private BaseBiGrpcService baseBiGrpcService;


    /**
     * @param project
     * @param columnDTOs
     * @param datasourceType
     * @return
     */
    public Map<String, ColumnDTO> getColumnDTOMap(ProjectDO project, List<ColumnDTO> columnDTOs, int datasourceType) {
        Map<String, ColumnDTO> columnDTOMap;

        // 根据不同的数据源类型做不同的处理
        if (datasourceType == DatasourceEnum.SURVEY.getIndex()
                || !ObjectUtils.isEmpty(project.getSurveyId())) { // 问卷类型数据源数据处理
            // 问卷项目 field.value == column.col
            columnDTOMap = columnDTOs.stream()
                    .collect(Collectors.toMap(ColumnDTO::getCol, self -> self, (prev, now) -> prev));
        } else {
            // 普通项目 field.id == column.id
            columnDTOMap = columnDTOs.stream()
                    .collect(Collectors.toMap(ColumnDTO::getId, self -> self, (prev, now) -> prev));
        }

        return columnDTOMap;
    }

    /**
     * 获取问卷项目训练字段的真实字段名
     *
     * @param textFieldList 问卷项目字段信息
     * @return Real filed name
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/6/23 14:32
     */
    public List<AnalysisProject.TextField> getRealFiled(List<AnalysisProject.TextField> textFieldList) {
        for (AnalysisProject.TextField field : textFieldList) {
            field.setValue(surveyTxtanlsFieldDao.findFieldColName(field.getId()));
        }
        return textFieldList;
    }

    /**
     * 从 mongo 中获取项目已有原话记录的最大记录时间
     *
     * @param projectId 项目id
     * @param filedId   字段id
     * @return The maximum recordTime of the previous training
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/6/9 14:23
     */
    public String getMaxTimeFromMongo(String projectId, String filedId) {
        String maxTime = recordDao.findMaxCollectionTime(projectId, filedId);
        if (ObjectUtils.isEmpty(maxTime)) {
            maxTime = recordDao.findMaxCreatedDt(projectId, filedId);
        }
        return maxTime;
    }

    /**
     * 从 mongo 中获取项目已有原话记录的最大index
     *
     * @param projectId 项目id
     * @param filedId   字段id
     * @return The maximum index of the previous training
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/6/23 10:55
     */
    public Integer getMaxIndexFromMongo(String projectId, String filedId) {
        // String maxIndex = recordDao.findMaxCollectionId(projectId, filedId);
        // if (ObjectUtils.isEmpty(maxIndex)) {
        //     return 0;
        // }
        // return Integer.parseInt(maxIndex, 10);
        return (int) recordDao.countProjectFieldRecord(projectId, filedId);
    }

    /**
     * 项目已有原话记录的数量
     *
     * @param projectId 项目id
     * @return The number of all records in the project
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/6/23 14:25
     */
    public long getExistedDataCount(String projectId) {
        return recordDao.countProjectAllRecord(projectId);
    }


    /**
     * 更新训练进度
     *
     * @author gy.liu
     * @date 2021/6/4
     */
    public void updateTrainProgress(String projectId, String fieldId, int count) {
        try {
            //更新训练进度缓存
            ProjectDO project = analysisProjectDao.findById(projectId);
            if (Objects.isNull(project)) {
                log.warn("[Txtanls] 更新项目 {} 训练状态时项目被删除", projectId);
                return;
            }
            if (TrainStatusEnum.FINISHED.getIndex() == project.getTrainStatus()) {
                return;
            }
            int trainProgress = project.getTrainProgress() - count;
            analysisProjectDao.updateAnalysisProjectProgress(projectId, TrainStatusEnum.UNFINISHED, trainProgress);
            if (log.isInfoEnabled()) {
                log.info("[Txtanls] 更新项目 {} 字段 {} 训练状态成功, 剩余数量 {}", projectId, fieldId, trainProgress);
            }
        } catch (Exception e) {
            log.error("[Txtanls] 更新项目 {} 字段 {} 训练状态失败; ErrorMessage: {}", projectId, fieldId, e.getMessage(), e);
        }
    }


    /**
     * 根据 worktableId 获取表的数据列信息
     *
     * @return Worktable all column Info
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/6/2 15:48
     */
    public List<ColumnDTO> getColumnInfo(String worktableId) {
        return baseBiGrpcService.listColumnByWorktableId(worktableId);
    }

    /**
     * 情感接口返回结果处理
     *
     * @author gy.liu
     * @date 2021/6/4
     */
    public List<SentimentDTO> responseParse(List<TextSentiment> sentiments) {
        // 根据不同的接口处理不同的返回值，这里获取句子观点以及观点情感和原句情感,使用自建模型，获取句子包含观点的时候不做区分
        List<SentimentDTO> result = new ArrayList<>();
        List<OpinionSentiment> opinionSentiments;
        for (TextSentiment sentiData : sentiments) {
            List<Map<String, Object>> allView = new ArrayList<>();
            opinionSentiments = sentiData.getOpinionSentimentsList();
            //每句原话会有多个观点情感
            for (OpinionSentiment opinion : opinionSentiments) {
                Map<String, Object> viewInfo = new HashMap<>();
                viewInfo.put("key", opinion.getOpinion());
                viewInfo.put("score", opinion.getLegacyOpinionSentimentCode());
                allView.add(viewInfo);
            }
            result.add(new SentimentDTO(sentiData.getLegacyTextSentimentCode(), allView));
        }
        return result;
    }

    /**
     * 观点转换
     *
     * @return List<Viewpoint>
     * @author gy.liu
     * @date 2021/6/4
     */
    public List<JoinInfo.Viewpoint> viewPointConvert(List<ViewpointDO> childrenViewPoint, List<Map<String, Object>> sentiViews) {
        List<JoinInfo.Viewpoint> listViewPoint = new ArrayList<>();
        for (ViewpointDO child : childrenViewPoint) {
            for (Map<String, Object> sentiView : sentiViews) {
                if (!child.getRowContent().equals(sentiView.get("key"))) {
                    continue;
                }
                if (RecordSentiEnum.NONE.getIndex() == (int) sentiView.get("score")) {
                    continue;
                }
                JoinInfo.Viewpoint viewPoint = new JoinInfo.Viewpoint();
                viewPoint.setKey((String) sentiView.get("key"));
                viewPoint.setViewId(child.getId());
                viewPoint.setValues((Integer) sentiView.get("score"));
                viewPoint.setContent(child.getViewContent());
                listViewPoint.add(viewPoint);
            }
        }
        return listViewPoint;
    }


    /**
     * 根据行业信息获取训练时使用的行业名称
     *
     * @param industryDTO 行业信息
     * @return Industry name used during training
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/6/10 15:31
     */
    public IndustryCodeEnum getBusiness(IndustryDTO industryDTO) {
        // 训练原话观点情感
        IndustryCodeEnum business = IndustryCodeEnum.DIET;
        if (Objects.nonNull(industryDTO) && Objects.nonNull(industryDTO.getCode())) {
            business = IndustryCodeEnum.getByCode(Integer.parseInt(industryDTO.getCode()));
        }
        return business;
    }

    /**
     * 时间格式化为 yyyy-MM-dd HH:mm:ss 格式
     *
     * @param time 待格式化的时间
     * @return 格式化后的时间
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/6/28 16:05
     */
    public static String formatToNewTime(String time) {
        if (ObjectUtils.isEmpty(time)) {
            return "";
        }
        if (time.length() > 18) {
            time = time.substring(0, 18);
        }

        // TODO: 未知时间格式格式化
        try {
            LocalDateTime parse = DateUtil.getLocalDateTime(time);
            return DateUtil.formatString(parse);
        } catch (Exception e1) {
            try {
                LocalDateTime parse = LocalDateTime.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-ddHH:mm:ss"));
                return DateUtil.formatString(parse);
            } catch (Exception e2) {
                return time;
            }
        }
    }


    /**
     * 时间格式化 替换'年'月'日'中文字符
     *
     * @param time 待格式化的时间
     * @return 格式化后的时间
     * @author XiaoYunSong <ys.xiao@idiaoyan.cn>
     * @date 2021/6/28 16:04
     */
    public String formatTime(String time) {
        // 处理时间
        String result = time;
        if (!ObjectUtils.isEmpty(time)) {
            result = result.replaceAll("[年月]", "-");
            result = result.replaceAll("日", "");
            result = result.trim();
        }
        return result;
    }

    /**
     * 保存原话记录
     *
     * @author gy.liu
     * @date 2021/6/4
     */
    public RecordDO saveRecord(ProjectDO project, TrainTextDTO trainTextDTO, int senti,
                               ProjectFieldDO textField, String industryId) {
        RecordDO recordDOEntity = new RecordDO();
        recordDOEntity.setId(StringUtil.getId());
        recordDOEntity.setSentiScore(0);
        recordDOEntity.setSenti(senti);
        recordDOEntity.setContent(trainTextDTO.getText());
        recordDOEntity.setSurveyId(project.getSurveyId());
        recordDOEntity.setFieldId(textField.getId());
        recordDOEntity.setFieldName(textField.getValue());
        recordDOEntity.setWorkTableId(project.getTableId());
        recordDOEntity.setWorkName(project.getTableName());
        recordDOEntity.setProjectId(project.getId());
        // 时间格式化
        recordDOEntity.setRecordTime(formatToNewTime(trainTextDTO.getTime()));
        recordDOEntity.setIndustryId(industryId);
        recordDOEntity.setCollectionId(trainTextDTO.getCollectionId());
        recordDOEntity.setCollectionTime(formatToNewTime(trainTextDTO.getCollectionTime()));
        return recordDao.insertRecord(recordDOEntity);
    }

    /**
     * 保存原话记录新
     *
     * @author gy.liu
     * @date 2021/6/4
     */
    public RecordDO saveRecordNew(ProjectDO project, String time, String colletionId, String text, int senti,
                                  ProjectFieldDO textField, String industryId) {
        RecordDO recordDOEntity = new RecordDO();
        recordDOEntity.setId(StringUtil.getId());
        recordDOEntity.setSentiScore(0);
        recordDOEntity.setSenti(senti);
        recordDOEntity.setContent(text);
        recordDOEntity.setSurveyId(project.getSurveyId());
        recordDOEntity.setFieldId(textField.getId());
        recordDOEntity.setFieldName("texts");
        recordDOEntity.setWorkTableId(project.getTableId());
        recordDOEntity.setWorkName("餐饮数据源demo");
        recordDOEntity.setProjectId(project.getId());
        // 时间格式化
        recordDOEntity.setRecordTime(formatToNewTime(time));
        recordDOEntity.setIndustryId(industryId);
        recordDOEntity.setCollectionId(colletionId);
        recordDOEntity.setCollectionTime(time);
        return recordDao.insertRecord(recordDOEntity);
    }

    /**
     * 保存训练结果
     *
     * @author gy.liu
     * @date 2021/6/4
     */
    public void saveJoinInfo(String projectId, TrainTextDTO trainTextDTO, int senti, String recordId,
                             List<JoinInfo.Viewpoint> listViewPoint) {

        if (CollUtil.isNotEmpty(listViewPoint)) {
            String mongoId =ObjectId.next();
            List<JoinInfoViewpointEntity> joinInfoViewpointEntities = new ArrayList<>(listViewPoint.size());
            listViewPoint.forEach(viewpoint -> {
                JoinInfoViewpointEntity joinInfoViewpointEntity = new JoinInfoViewpointEntity();
                // id
                joinInfoViewpointEntity.setId(ObjectId.next());
                // 项目id
                joinInfoViewpointEntity.setProjectId(projectId);
                // 原话记录id
                joinInfoViewpointEntity.setRecordId(recordId);
                // 	观点原内容
                joinInfoViewpointEntity.setRowContent(viewpoint.getKey());
                // 	观点翻译内容
                joinInfoViewpointEntity.setViewContent(viewpoint.getContent());
                // 观点情感
                joinInfoViewpointEntity.setViewSenti(viewpoint.getValues());
                joinInfoViewpointEntity.setSample(false);
                // mongoId，数据迁移使用
                joinInfoViewpointEntity.setMongoId(mongoId);
                // 观点id
                joinInfoViewpointEntity.setViewId(viewpoint.getViewId());
                joinInfoViewpointEntity.setCreateTime(DateUtil.getCommonDate());
                joinInfoViewpointEntity.setUpdateTime(DateUtil.getCommonDate());
                joinInfoViewpointEntities.add(joinInfoViewpointEntity);
            });
            joinInfoDao.insertJoinInfo(joinInfoViewpointEntities);
        }
    }

    /**
     * 保存训练结果新
     *
     * @author gy.liu
     * @date 2021/6/4
     */
    public void saveJoinInfoNew(String projectId, String time, String collectionId, int senti, String recordId,
                                List<JoinInfo.Viewpoint> listViewPoint) {
        if (CollUtil.isNotEmpty(listViewPoint)) {
            List<JoinInfoViewpointEntity> joinInfoViewpointEntities = new ArrayList<>(listViewPoint.size());
            listViewPoint.forEach(viewpoint -> {
                JoinInfoViewpointEntity joinInfoViewpointEntity = new JoinInfoViewpointEntity();
                // id
                joinInfoViewpointEntity.setId(ObjectId.next());
                // 项目id
                joinInfoViewpointEntity.setProjectId(projectId);
                // 原话记录id
                joinInfoViewpointEntity.setRecordId(recordId);
                // 	观点原内容
                joinInfoViewpointEntity.setRowContent(viewpoint.getKey());
                // 	观点翻译内容
                joinInfoViewpointEntity.setViewContent(viewpoint.getContent());
                // 观点情感
                joinInfoViewpointEntity.setViewSenti(viewpoint.getValues());
                // 观点id
                joinInfoViewpointEntity.setViewId(viewpoint.getViewId());
                joinInfoViewpointEntity.setCreateTime(DateUtil.getCommonDate());
                joinInfoViewpointEntity.setUpdateTime(DateUtil.getCommonDate());
                joinInfoViewpointEntities.add(joinInfoViewpointEntity);
            });
            joinInfoDao.insertJoinInfo(joinInfoViewpointEntities);
        }
    }
}
